package com.jh.paymentchannel.service;

import java.io.UnsupportedEncodingException;
import java.math.RoundingMode;
import java.net.URI;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import com.jh.paymentchannel.util.Util;
import com.jh.paymentchannel.util.ump.paygate.v40.HttpRequest;
import com.jnewsdk.connection.client.HttpClient;
import com.jnewsdk.connection.client.HttpSSLClient;
import com.jnewsdk.tools.log.LogFactory;
import com.jnewsdk.util.Base64;
import com.jnewsdk.util.SignUtil;
import com.jnewsdk.util.StringUtils;

import cn.jh.common.utils.CommonConstants;
import cn.jh.common.utils.Md5Util;
import net.sf.json.JSONObject;
@Controller
@EnableAutoConfiguration
public class KjTopupRequest {
private static final Logger log = LoggerFactory.getLogger(KjTopupRequest.class);
	
	@Value("${kuaijie.req_url}")
	private String req_url;
	
	@Value("${kuaijie.merchant_key}")
	private String merchant_key;
	
	@Value("${kuaijie.merchant_no}")
	private String merchant_no;
	
	@Value("${payment.ipAddress}")
	private String ipAddress;
	
	@Autowired
	Util util;
	
		// 需做Base64加密
		private final String[] base64Keys = new String[] { "subject", "body", "remark" };
		// 需做Base64加密,并所有子域采用json数据格式
		private final String[] base64JsonKeys = new String[] { "customerInfo", "accResv", "riskRateInfo", "billQueryInfo","billDetailInfo" };
		private static final String URL_PARAM_CONNECT_FLAG = "&";
		public static final Set<String> base64Key = new HashSet<String>();
		static {
			base64Key.add("subject");
			base64Key.add("body");
			base64Key.add("remark");
			base64Key.add("customerInfo");
			base64Key.add("accResv");
			base64Key.add("riskRateInfo");
			base64Key.add("billpQueryInfo");
			base64Key.add("billDetailInfo");
			base64Key.add("respMsg");
			base64Key.add("resv");
		}
	
	@RequestMapping(method=RequestMethod.POST,value="/v1.0/paymentchannel/topup/kj/request")
	public @ResponseBody Object topupRequest(HttpServletRequest request,
			@RequestParam(value = "bankName") String bankName,
			@RequestParam(value = "amount") String amount,
			@RequestParam(value = "ordercode") String ordercode,
			 @RequestParam(value = "bankBranchName") String bankBranchName,
			 @RequestParam(value = "province") String province,
			 @RequestParam(value = "city") String city,
			 @RequestParam(value = "bankBranchId") String lineNoJJ,
			 @RequestParam(value = "securityCode") String securityCode,
			 @RequestParam(value = "expiredTime") String expiredTime,
			 @RequestParam(value = "channelParam") String channelParam
			 )
			throws Exception {
		log.info("接口/v1.0/transactionclear/payment/query/ordercode--参数================"+lineNoJJ+"/"+city+"/"+province+"/"+bankBranchName+"/"+ordercode+"/"+amount+"/"+bankName);
		/**根据订单号获取相应的订单*/
		String bankcard =null;//信用卡卡号
		String phone = null;//预留信用卡手机号码
		String idcardJJ = null;//借记卡账户身份证号
		String idcard = null;//身份证号
		String bankNameX = null;//信用卡银行名
		String userNameJJ = null;//借记卡用户姓名
		String userName = null;//信用卡用户姓名
		long userid = 0;//用户ID
		String cardNo = null;//借记卡卡号
		String telphone = null;//借记卡预留手机号
		String priOrPub = null;//对私还是对公帐户
		String priOrPubJJ = null;
		String desc = null;//显示页面描述
		String brandname = null;//商品名称,用于显示在支付界面 
		String channelid = null;
		String extraFee = null;
		
		Map maps = new HashMap();
		{
		RestTemplate restTemplate=new RestTemplate();
		URI uri = util.getServiceUrl("transactionclear", "error url request!");
		String url = uri.toString() + "/v1.0/transactionclear/payment/query/ordercode";
		MultiValueMap<String, String> requestEntity  = new LinkedMultiValueMap<String, String>();
		requestEntity.add("order_code", ordercode);
		JSONObject resultObj = null;
		try {
			String result = restTemplate.postForObject(url, requestEntity, String.class);
			log.info("接口/v1.0/transactionclear/payment/query/ordercode--RESULT================"+result);
			JSONObject jsonObject =  JSONObject.fromObject(result);
			resultObj = jsonObject.getJSONObject("result");
		} catch (Exception e) {
			log.error("查询订单有误====="+e);
			maps.put(CommonConstants.RESP_CODE, "failed");
			maps.put(CommonConstants.RESP_MESSAGE, "查询订单信息有误");
			return maps;
		}
		bankcard =  resultObj.getString("bankcard");
		desc = resultObj.getString("desc");
		channelid = resultObj.getString("channelid");
		brandname = resultObj.getString("brandname");
		 extraFee = resultObj.getString("extraFee");
		}	
		if(bankcard == null || bankcard.equalsIgnoreCase("")){
			return null;
		}
		
		{
			/**根据订单号获取相应的订单*/
			RestTemplate restTemplate=new RestTemplate();
			URI uri = util.getServiceUrl("user", "error url request!");
			String url = uri.toString() + "/v1.0/user/bank/default/cardno";
			MultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<String, String>();
			requestEntity.add("cardno", bankcard);
			requestEntity.add("type", "0");
			String result = restTemplate.postForObject(url, requestEntity, String.class);
			log.info("接口/v1.0/user/bank/default/cardno--RESULT================"+result);
			JSONObject jsonObject =  JSONObject.fromObject(result);
			JSONObject resultObj  =  jsonObject.getJSONObject("result");
			if(resultObj==null){
				return null;
			}
			 //expiredTime = resultObj.getString("expiredTime");//付款信用卡有效期,格式YYMM
			 //securityCode = resultObj.getString("securityCode");//付款信用卡安全码
			 phone = resultObj.getString("phone"); //预留信用卡手机号码
			 //lineNo = resultObj.getString("lineNo");//联行行号
			 idcard = resultObj.getString("idcard");//身份证号
			 bankNameX = resultObj.getString("bankName");//信用卡银行名
			 priOrPub = resultObj.getString("priOrPub");//对私还是对公帐户
			 userName = resultObj.getString("userName");//用户姓名
			 userid = resultObj.getLong("userId");//用户ID
			
			restTemplate=new RestTemplate();
			uri = util.getServiceUrl("user", "error url request!");
			url = uri.toString() + "/v1.0/user/bank/default/userid";
			requestEntity  = new LinkedMultiValueMap<String, String>();
			requestEntity.add("user_id", String.valueOf(userid));
			result = restTemplate.postForObject(url, requestEntity, String.class);
			String respCode = "";
			log.info("接口/v1.0/user/bank/default/userid--RESULT================"+result);
			try {
				jsonObject =  JSONObject.fromObject(result);
				resultObj  =  jsonObject.getJSONObject("result");
				respCode  =  jsonObject.getString("resp_code");
			} catch (Exception e) {
				log.error("查询结算卡异常" + e.getMessage());
				Map map = new HashMap();
				map.put("resp_code", "failed");
				map.put("resp_message", "没有结算卡");
				return map;
			}
			
			if(!"000000".equals(respCode)){
				Map map = new HashMap();
				map.put("resp_code", "failed");
				map.put("resp_message", "没有结算卡");
				return map;
			}
			
			 cardNo = resultObj.getString("cardNo");//借记卡卡号
			 //lineNoJJ = resultObj.getString("lineNo");//借记卡联行行号
			 telphone = resultObj.getString("phone");//借记卡预留手机号
			 priOrPubJJ = resultObj.getString("priOrPub");
			 userNameJJ = resultObj.getString("userName");//借记卡用户姓名
			 idcardJJ = resultObj.getString("idcard");//借记卡账户身份证号
		}
		URI uri = util.getServiceUrl("user", "error url request!");
		String road = uri.toString() + "/v1.0/user/channel/rate/query/userid";
		
		/**根据的渠道标识或去渠道的相关信息*/
		MultiValueMap<String, String> requestEntity  = new LinkedMultiValueMap<String, String>();
		requestEntity.add("channel_id", channelid);
		requestEntity.add("user_id", String.valueOf(userid));
		RestTemplate restTemplate=new RestTemplate();
		JSONObject jsonObject = null;
		try {
			String resultObjx = restTemplate.postForObject(road, requestEntity, String.class);
			log.info("接口/v1.0/user/channel/rate/query/userid--RESULT================"+resultObjx);
			jsonObject = JSONObject.fromObject(resultObjx);
		} catch (Exception e) {
			log.error("查询费率有误====="+e);
			maps.put(CommonConstants.RESP_CODE, "failed");
			maps.put(CommonConstants.RESP_MESSAGE, "查询费率信息有误");
			return maps;
		}
		
		if(!CommonConstants.SUCCESS.equals(jsonObject.getString(CommonConstants.RESP_CODE))){
			Map<String,String>map = new HashMap<String,String>();
			map.put(CommonConstants.RESP_CODE,CommonConstants.FALIED);
			map.put(CommonConstants.RESP_MESSAGE, "亲.支付失败,臣妾已经尽力了,请重试!");
			return map;
		}
		
		JSONObject resultObj  =  jsonObject.getJSONObject("result");
		String rate = resultObj.getString("rate");	
		Double rat = Double.parseDouble(rate)*100;
		DecimalFormat decimalFormat = new DecimalFormat("0.00");
		decimalFormat.setRoundingMode(RoundingMode.CEILING);
		
		String withdrawFee = resultObj.getString("withdrawFee");
		
		log.info("传过来的  channelParam======="+channelParam);
		String index = "3";
		if(null != channelParam && "kuaijiecoin".equals(channelParam)) {
			index = "4";
		}
		
		log.info("最终确定的   index======="+index);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		Map<String, Object> map = new TreeMap<String, Object>(
		         new Comparator<String>() {
		             @Override
					public int compare(String obj1, String obj2) {
		             return obj1.compareTo(obj2);
		           }
		        });
				map.put("bankNo", cardNo);		//开户卡号   @
				map.put("bankName", bankName); //开户行名称(请参考总行.xlsx)  @
				map.put("payBankCardIdNo", idcard); //付款信用卡持卡人身份证号  @
				map.put("cardNo", idcardJJ); //开户人身份证号码  @
				map.put("tel", telphone);  //银行预留手机号     @
				map.put("payBankCardPhone", phone);   //付款信用卡预留手机号    @
				map.put("payBankCardAccountName",userName);   //付款信用卡持卡人姓名(请务必保证与realName参数一致)   @
				map.put("realName", userNameJJ);  //开户人姓名   @
				map.put("settlePeriod", 1); //结算周期，1：T0实时结算，支付成功后，立马结算2：T1隔天结算   @
				map.put("settleFeeRate", decimalFormat.format(rat));  //结算给您的客户的费率(0.60表示百分之0.60)（您给您的客户的费率），必须高于商户费率比如 交易金额是 100，   @
											   //settleFeeRate是百分之 0.60（必须高于您的费率）那么 您的客户实际收到的金额是100 * （1 – settleFeeRate / 100）- 商户代付手续费-代付手续费(此手续费由我们设置)
				map.put("merchantNo", merchant_no);  //商户号-测试环境统一商户号    @
				map.put("outTradeNo",ordercode.substring(0, 30));  	//商户号订单号-最小6位最大64位    @
				map.put("payType", index);    //支付类型：4有积分,3无积分   @
				map.put("payBankCardNo", bankcard);  		//付款信用卡卡号	 @
				Double amt = Double.valueOf(amount);
				DecimalFormat df = new DecimalFormat("0.00");//格式化
				String CNY = df.format(amt);
				map.put("amount", CNY);		//交易金额以元为单位，如：10.00表示为10元）	  @
				map.put("payBankCardName", bankNameX);  //付款信用卡银行名称(请参考总行.xlsx)  @
				map.put("agentFee", extraFee); //商户代付手续费(保留参数，暂不生效)  @
				map.put("payBankCardExpiredDate", expiredTime);  //付款信用卡有效期,格式YYMM  @
				map.put("payBankCardCVN", securityCode);  //付款信用卡安全码  @
				map.put("bankBranchId", lineNoJJ); //联行行号  @
				map.put("address", province+city);  //详细地址  @
				map.put("city", city);  //开户行所在市  @
				map.put("province", province); //开户行所在省份  @
				map.put("bgUrl",ipAddress+"/v1.0/paymentchannel/topup/kj/notify_call");     	//订单状态回调回调地址    ？
				map.put("pageUrl", ipAddress+"/v1.0/paymentchannel/topup/kj/ret_url");  //重定向地址  @
				map.put("bankBranchName", bankBranchName);  //开户支行名称  @
				map.put("goodsName", brandname.trim());  //商品名称,用于显示在支付界面  @  	
				map.put("goodsDesc", desc); //商品描述  @
  			    map.put("bankType", 2);   //卡类型2:对私1:对公		@	
		
		
		Set removeKey = new HashSet();
		//拼接字符串
	    //String signMsg = SignUtil.getSignMsg(map, removeKey);
  		String signMsg = Md5Util.MapValuetoString(map);
  		signMsg = Md5Util.mapKey2String(map);
	    log.info("拼接字符串——signMsg@"+signMsg);
	    //String signMethod = request.getParameter("signMethod");
	    String key = merchant_key;
	    //String signa = SignUtil.sign("MD5", signMsg, key, "UTF-8");
	    String signature = Md5Util.getMD5(signMsg+key);
	    System.out.println(signMsg+key);
	    System.out.println("signature:"+signature);
	    map.put("sign", signature);  //加密字符串，加密方式见4.1  @
	    log.info("kuaijietopupRequest——map@"+map.toString());
	    //converData(map);
	    //String reqMsg = SignUtil.getURLParam(map, false, null);
		//log.info("kuaijietopupRequest——reqMsg"+reqMsg);
		String url = req_url;
		//String msgg = sendMsg(url, map);
		JSONObject jsonobj = new JSONObject();
		jsonobj = jsonobj.fromObject(map);
		log.info("kuaijietopupRequest——jsonobj@"+jsonobj);
		//String msg = HttpRequest.sendPost(url, jsonobj.toString());
		String msg = HttpRequest.sendPostJSON(url, jsonobj);
		JSONObject json = JSONObject.fromObject(msg);  
		msg = json.toString();
		/*String errm = null;
		if(json.containsKey("errMsg"))
			errm = json.getString("errMsg");
		msg = unicode2String(errm);*/
		//String msgg = sendMsg(url,jsonobj);
		log.info("kuaijietopupreturn——msg@"+msg);
		Map mapp = new HashMap();
		if (StringUtils.isEmpty(msg)) {
			request.setAttribute("RespCode", "9999");
			request.setAttribute("RespMsg", "报文发送失败或应答消息为空");
			log.info(SignUtil.parseParam(request).toString());
			mapp.put("resp_code", "fail");	
			mapp.put("resp_message", "报文发送失败或应答消息为空");	
	        return mapp;
		} else {
			log.info("收到结果：" + msg);
			String status = json.getString("status");
			log.info("status：" + status);
			if (status.equals("0000")) {	
					mapp.put("resp_code", "success");	
					mapp.put("channel_type", "kuaijie");
					mapp.put("result", msg);
					return mapp;
			} else {
				request.setAttribute("RespCode", "9999");
				JSONObject obj = json.getJSONObject("msg");
				String errMsg = obj.getString("errMsg");
				request.setAttribute("RespMsg", errMsg);
				log.info(request.getAttribute("RespMsg").toString());
				mapp.put("resp_code", "fail");	
				mapp.put("resp_message", errMsg);
				return mapp;
			}
		}    
	    
	}
	
	/**
	  * unicode 转字符串
	 */
	public static String unicode2String(String unicode) {
	  
	     StringBuffer string = new StringBuffer();
	  
	     String[] hex = unicode.split("\\\\u");
	  
	     for (int i = 1; i < hex.length; i++) {
	  
	         // 转换出每一个代码点
	        int data = Integer.parseInt(hex[i], 16);
	  
	         // 追加成string
	         string.append((char) data);
	     }
	  
	     return string.toString();
	 }
	
	/**
	 * 设置签名
	 * 
	 * @param paramMap
	 */
	protected  void setSignature(Map<String, String> paramMap) {
		String key =merchant_key;
		String signMethod = paramMap.get("signMethod");
		Set<String> removeKey = new HashSet<String>();
		removeKey.add("signMethod");
		removeKey.add("signature");
		String signMsg = SignUtil.getSignMsg(paramMap, removeKey);		
		String signature = SignUtil.sign(signMethod, signMsg, key, "UTF-8");
		
//		若签名有时能过有时不能过,请把+号做转义后再测试
//		+号做转义
		if(signature.indexOf("+")!=-1){
			signature = signature.replaceAll("\\+", "%2B");
		}
		
		paramMap.put("signature", signature);
		
	}
		

	/**
	 * 转换特殊字段
	 * @param paramMap
	 */
	protected  void converData(Map<String, String> paramMap) {
		for (int i = 0; i < base64Keys.length; i++) {
			String key = base64Keys[i];
			String value = (String) paramMap.get(key);
			if (StringUtils.isNotEmpty(value)) {
				try {
					String text = new String(Base64.encode(value.getBytes("UTF-8")));
					// 更新请求参数
					paramMap.put(key, text);
				} catch (Exception e) {
				}
			}
		}
		for (int i = 0; i < base64JsonKeys.length; i++) {
			String key = base64JsonKeys[i];
			String value = (String) paramMap.get(key);
			if (StringUtils.isNotEmpty(value)) {
				try {
					String text = new String(Base64.encode(value.getBytes("UTF-8")));
					// 更新请求参数
					paramMap.put(key, text);
				} catch (Exception e) {
				}
			}
		}
	}
	
	/**
	 * 往渠道发送数据
	 * 
	 * @param url
	 *            通讯地址
	 * @param paramMap
	 *            发送参数
	 * @return 应答消息
	 */
	protected String sendMsg(String url, JSONObject obj) {
		try {
			HttpClient http = new HttpSSLClient(url, "60000");
			http.setRequestMethod("POST");
			http.connect();
			// 转换参数格式
			//String webForm = getWebForm(paramMap);
			http.send(obj.toString().getBytes());
			byte[] rspMsg = http.getRcvData();
			String msg = new String(rspMsg, "utf-8");
			LogFactory.getLog().info(this, msg);
			return msg;
		} catch (Exception e) {
			LogFactory.getLog().error(e, e.getMessage());
		}
		return null;
	}
	
	/**
	 * 将map转化为形如key1=value1&key2=value2...
	 * 
	 * @param map
	 * @return
	 */
	protected String getWebForm(Map<String, String> map) {
		if (null == map || map.keySet().size() == 0) {
			return "";
		}
		StringBuffer url = new StringBuffer();
		for (Map.Entry<String, String> entry : map.entrySet()) {
			String value = entry.getValue();
			String str = (value != null ? value : "");
			try {
				str = URLEncoder.encode(str, "UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			url.append(entry.getKey()).append("=").append(str).append(URL_PARAM_CONNECT_FLAG);
		}

		// 最后一个键值对后面的“&”需要去掉。
		String strURL = "";
		strURL = url.toString();
		if (URL_PARAM_CONNECT_FLAG.equals("" + strURL.charAt(strURL.length() - 1))) {
			strURL = strURL.substring(0, strURL.length() - 1);
		}
		return (strURL);
	}
	
	/**
	 * 转换报文格式及特殊字段base64解码
	 * 
	 * @param msg
	 * @return
	 */
	public Map parseMsg(String msg) {
		Map map = SignUtil.parseResponse(msg);
		// 特殊字段base64解码
		for (Iterator iterator = base64Key.iterator(); iterator.hasNext();) {
			String key = (String) iterator.next();
			String value = (String) map.get(key);
			if (StringUtils.isNotEmpty(value)) {
				try {
					String text = new String(Base64.decode(value.toCharArray()), "UTF-8");
					map.put(key, text);
				} catch (Exception e) {
				}
			}
		}
		return map;
	}
	
	/**
	 * 验签
	 * 
	 * @param paramMap
	 * @return
	 */
	public boolean verifySign(Map paramMap) {
		// 计算签名
		Set<String> removeKey = new HashSet<String>();
		removeKey.add("signMethod");
		removeKey.add("signature");
		String signedMsg = SignUtil.getSignMsg(paramMap, removeKey);
		String signMethod = (String) paramMap.get("signMethod");
		String signature = (String) paramMap.get("signature");
		// 密钥
		String key =merchant_key;
		return SignUtil.verifySign(signMethod, signedMsg, signature, key, "UTF-8");
	}
}
